package cn.dyw.engine.core.template;

import cn.dyw.engine.core.context.DynamicFilterParameter;
import cn.dyw.engine.core.utils.DateUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.ReflectiveMethodExecutor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 解析字段名
 *
 * @author dyw770
 * @since 2021-08-04
 */
@Slf4j
public class DynamicFilterPlaceholderResolver {

    @Getter
    @Setter
    private ExpressionParser parser;

    @Getter
    @Setter
    private EvaluationContext evaluationContext;

    public DynamicFilterPlaceholderResolver() {
        parser = new SpelExpressionParser();
        evaluationContext = defaultEvaluationContext();
    }

    public DynamicFilterPlaceholderResolver(ExpressionParser parser, EvaluationContext evaluationContext) {
        this.parser = parser;
        this.evaluationContext = evaluationContext;
    }

    /**
     * 解析占位符的值
     *
     * @param placeholderName 占位符名字
     * @param parameters      参数列表
     * @return 解析出的值
     */
    public String resolvePlaceholder(String placeholderName, Map<String, DynamicFilterParameter> parameters) {
        DynamicFilterParameter parameter = parameters.get(placeholderName);

        // 解析出来的占位符如果能直接在参数列表中取出来，则直接返回
        // TODO 这里以后考虑参数类型为其他的情况
        if (!ObjectUtils.isEmpty(parameter)) {
            String parameterValue = parameter.getParameterValue();
            log.debug("渲染参数：[{}] 参数值: [{}]", placeholderName, parameterValue);
            return parameterValue;
        }

        // 当查询不到参数时则通过表达式计算
        HashMap<String, Object> rootObj = new HashMap<>(16);

        Set<String> keys = parameters.keySet();
        for (String key : keys) {
            rootObj.put(key, parameters.get(key).getParameterValue());
        }

        Expression exp = parser.parseExpression(placeholderName);
        String expValue = exp.getValue(evaluationContext, rootObj, String.class);
        log.debug("渲染参数：[{}] 参数值: [{}]", placeholderName, expValue);
        return expValue;
    }

    /**
     * 默认的EvaluationContext
     *
     * @return EvaluationContext
     */
    public static EvaluationContext defaultEvaluationContext() {
        EvaluationContext evaluationContext =
                SimpleEvaluationContext.
                        forPropertyAccessors(new MapAccessor())
                        .withMethodResolvers((context, targetObject, name, argumentTypes) -> {
                            Object o = context.lookupVariable(name);
                            if (o instanceof Method) {
                                return new ReflectiveMethodExecutor((Method) o);
                            }
                            return null;
                        }).build();

        addEvaluationContext(evaluationContext);
        return evaluationContext;
    }

    /**
     * 注册默认的方法
     *
     * @param evaluationContext evaluationContext
     */
    public static void addEvaluationContext(EvaluationContext evaluationContext) {
        // TODO 注册默认的方法
        try {
            evaluationContext.setVariable("reverse",
                    DateUtils.class.getDeclaredMethod("reverse", String.class));
        } catch (NoSuchMethodException e) {
            log.error("添加默认的el方法出现异常", e);
        }
    }
}
